最佳实践 | 助您提升应用的无障碍功能
Android 提供了一些系统无障碍服务,其中包括:
TalkBack: 帮助视力低下或失明的人。通过合成语音读出内容,并在应用中执行操作以响应用户手势。 开关控制: 帮助有运动障碍的人。突出显示互动元素,并执行操作以响应用户按某个按钮的动作。用户只使用 1 个或 2 个按钮就能控制设备。
TalkBack
https://support.google.com/accessibility/android/answer/6283677开关控制
https://support.google.com/accessibility/android/answer/6122836
标签元素: 用户应该能够理解应用中每个有意义的互动界面元素的内容和用途。 使用或扩展系统微件: 基于框架包含的视图元素构建,而不是创建您自己的自定义视图。框架的视图和微件类已经提供了应用所需的大多数无障碍功能。 使用除颜色之外的提示: 用户应该能够明确区分界面中的各类元素。为此,除了颜色之外,还应使用图案和位置表示这些差异。 让媒体内容使用起来更没有障碍: 尝试向应用的视频或音频内容添加说明,这样使用这些内容的用户就无需完全依靠视觉或听觉提示。
标签元素
可修改的元素
<!-- The hint text for en-US locale would be
"Apartment, suite, or building". -->
<EditText
android:id="@+id/addressLine2"
android:hint="@string/aptSuiteBuilding" ... />
EditText
https://developer.android.google.cn/reference/android/widget/EditText
给定的 EditText 元素通常会有一个相应的 View 对象,该对象描述了用户应在 EditText 元素中输入的内容。在搭载 Android 4.2 (API 级别 17) 或更高版本的设备上,您可以通过设置 View 对象的 android:labelFor 属性来指明这种关系。
View
https://developer.android.google.cn/reference/android/view/View
下面的代码段显示了为此类元素对添加标签的示例:
<!-- Label text for en-US locale would be "Username:" -->
<TextView
android:id="@+id/usernameLabel" ...
android:text="@string/username"
android:labelFor="@+id/usernameEntry" />
<EditText
android:id="@+id/usernameEntry" ... />
<!-- Label text for en-US locale would be "Password:" -->
<TextView
android:id="@+id/passwordLabel" ...
android:text="@string/password
android:labelFor="@+id/passwordEntry" />
<EditText
android:id="@+id/passwordEntry"
android:inputType="textPassword" ... />
集合中的元素
向集合中的元素添加标签时,每个标签都应该是唯一的。这样,系统的无障碍服务在读出标签时就可以特指屏幕上的 1 个元素。这种对应关系可让用户知道他们何时循环浏览界面,或何时将焦点移到了已经发现的元素。
需要特别注意的是,您应在重用布局内的元素 (如 RecyclerView 对象) 中添加更多文字或上下文信息,以便能够唯一标识每个子元素。
RecyclerView
https://developer.android.google.cn/reference/androidx/recyclerview/widget/RecyclerView
为此,请在适配器实现中设置内容说明,如以下代码段所示
data class MovieRating(val title: String, val starRating: Integer)
class MyMovieRatingsAdapter(private val myData: Array<MovieRating>):
RecyclerView.Adapter<MyMovieRatingsAdapter.MyRatingViewHolder>() {
class MyRatingViewHolder(val ratingView: ImageView) :
RecyclerView.ViewHolder(ratingView)
override fun onBindViewHolder(holder: MyRatingViewHolder, position: Int) {
val ratingData = myData[position]
holder.ratingView.contentDescription = "Movie ${position}: " +
"${ratingData.title}, ${ratingData.starRating} stars"
}
}
相关内容组
如果应用显示的多个界面元素构成一个自然组 (如歌曲的详细信息或消息的属性),应将这些元素整理到一个容器中,该容器通常是 ViewGroup 的子类。将容器对象的 android:screenReaderFocusable 属性设为 true,并将每个内部对象的 android:focusable 属性设为 false。这样,无障碍服务就可以在单次语音中逐个读出内部元素的内容说明。这样整合相关元素有助于使用辅助技术的用户更高效地发现屏幕上的信息。
android:screenReaderFocusable
https://developer.android.google.cn/reference/android/view/View#attr_android:screenReaderFocusableandroid:focusable
https://developer.android.google.cn/reference/android/view/View#attr_android:focusable
<!-- In response to a single user interaction, accessibility services announce
both the title and the artist of the song. -->
<ConstraintLayout
android:id="@+id/song_data_container" ...
android:screenReaderFocusable="true">
<TextView
android:id="@+id/song_title" ...
android:focusable="false"
android:text="@string/my_song_title" />
<TextView
android:id="@+id/song_artist"
android:focusable="false"
android:text="@string/my_songwriter" />
</ConstraintLayout>
自定义组标签
<!-- In response to a single user interaction, accessibility services
announce the custom content description for the group. -->
<ConstraintLayout
android:id="@+id/song_data_container" ...
android:screenReaderFocusable="true"
android:contentDescription="@string/title_artist_best_song">
<TextView
android:id="@+id/song_title" ...
<!-- Content ignored by accessibility services -->
android:text="@string/my_song_title" />
<TextView
android:id="@+id/song_artist"
<!-- Content ignored by accessibility services -->
android:text="@string/my_songwriter" />
</ConstraintLayout>
嵌套组
<!-- In response to a single user interaction, accessibility services
announce the events for a single stage only. -->
<ConstraintLayout
android:id="@+id/festival_event_table" ... >
<ConstraintLayout
android:id="@+id/stage_a_event_column"
android:screenReaderFocusable="true">
<!-- UI elements that describe the events on Stage A. -->
</ConstraintLayout>
<ConstraintLayout
android:id="@+id/stage_b_event_column"
android:screenReaderFocusable="true">
<!-- UI elements that describe the events on Stage B. -->
</ConstraintLayout>
</ConstraintLayout>
文字中的标题
android:accessibilityHeading
https://developer.android.google.cn/reference/android/view/View#attr_android:accessibilityHeading
无障碍窗格标题
<!-- Accessibility services receive announcements about content changes
that are scoped to either the "shopping cart view" section (top) or
"browse items" section (bottom) -->
<MyShoppingCartView
android:id="@+id/shoppingCartContainer"
android:accessibilityPaneTitle="@string/shoppingCart" ... />
<MyShoppingBrowseView
android:id="@+id/browseItemsContainer"
android:accessibilityPaneTitle="@string/browseProducts" ... />
android:accessibilityPaneTitle
https://developer.android.google.cn/reference/android/R.attr#accessibilityPaneTitle
装饰性元素
https://developer.android.google.cn/reference/android/view/View#attr_android:contentDescriptionandroid:contentDescription
扩展系统微件
View
https://developer.android.google.cn/reference/kotlin/android/view/ViewViewCompat
https://developer.android.google.cn/reference/kotlin/androidx/core/view/ViewCompatCanvas
https://developer.android.google.cn/reference/kotlin/android/graphics/CanvasCanvasCompat
https://github.com/material-components/material-components-android/blob/master/lib/java/com/google/android/material/canvas/CanvasCompat.java让自定义视图使用起来更没有障碍
https://developer.android.google.cn/guide/topics/ui/accessibility/custom-views
Switch
https://developer.android.google.cn/reference/android/widget/Switch
从类层次结构最下方扩展
View
↳ TextView
↳ Button
↳ CompoundButton
↳ Switch
新的 TriSwitch 类最好直接从 Switch 类扩展。这样,Android 无障碍功能框架就可以提供 TriSwitch 类所需的大多数无障碍功能:
无障碍操作: 告知系统无障碍服务如何模拟在 TriSwitch 对象上执行的各种可能的用户输入。(继承自 View。) 无障碍事件: 告知无障碍服务当屏幕刷新或更新时,TriSwitch 对象的外观会发生的各种可能的变化方式。(继承自 View。) 特征: 有关每个 TriSwitch 对象的详细信息,例如其显示的任何文字的内容。(继承自 TextView。) 状态信息: TriSwitch 对象的当前状态的说明,如 "选中" 或 "未选中"。(继承自 CompoundButton。) 状态的文字说明: 文字类说明,解释了各种状态的含义。(继承自 Switch。)
定义自定义事件
当您扩展某个系统微件时,可能会改变用户与该微件互动方式的某一方面。请务必定义这些互动变化,以便无障碍服务可以更新应用的微件,就像用户直接与微件互动一样。
ViewCompat.replaceAccessibilityAction()
https://developer.android.google.cn/reference/androidx/core/view/ViewCompat#replaceAccessibilityAction(android.view.View,%20androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat,%20java.lang.CharSequence,%20androidx.core.view.accessibility.AccessibilityViewCommand)ViewCompat.performAccessibilityAction()
https://developer.android.google.cn/reference/androidx/core/view/ViewCompat#performAccessibilityAction(android.view.View,%20int,%20android.os.Bundle)
此原则如何对 TriSwitch 对象起作用
class TriSwitch(context: Context) : Switch(context) {
// 0, 1, or 2.
var currentState: Int = 0
private set
init {
updateAccessibilityActions()
}
private fun updateAccessibilityActions() {
ViewCompat.replaceAccessibilityAction(this, ACTION_CLICK,
action-label) {
view, args -> moveToNextState()
})
}
private fun moveToNextState() {
currentState = (currentState + 1) % 3
}
}
使用除颜色之外的提示
为了帮助有色觉缺陷的用户,请使用除颜色之外的提示区分应用屏幕中的界面元素。具体方法包括采用不同的形状或大小、提供文字或视觉图案,或者添加基于音频的反馈或基于轻触手势的触感反馈来表示元素的差异。
下图显示了一个 Activity 的两个版本。一个版本仅使用颜色区分工作流程中两种可能的操作。另一个版本采用了最佳做法: 除了颜色之外,还使用了形状和文字来突出两个选项之间的差异:
让媒体内容使用起来更没有障碍
如果您开发的应用包含视频剪辑或音频录音等媒体内容,应设法为具有不同类型的无障碍功能需求的用户提供支持,让他们能够理解此类内容。特别是,我们建议您做到以下几点:
添加可让用户暂停或停止播放媒体、调整音量以及切换字幕的控件。 如果视频提供的信息对于完成工作流程至关重要,应以其他格式提供相同的内容,如转录内容。
其他资源
如需详细了解如何让您的应用使用起来更没有障碍,请参阅下面列出的其他资源:
Codelab: 基本的 Android 无障碍功能
https://developer.android.google.cn/codelabs/starting-android-accessibility#0 博文: 无障碍功能: 是否所有用户都能使用您的应用? https://android-developers.googleblog.com/2012/04/accessibility-are-you-serving-all-your.html
推荐阅读